#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/times.h>
#include <unistd.h>
#include <sys/types.h>

#include "my_pthread.h"
#include "shm.h"
#include <sys/ipc.h>
#include <sys/shm.h>


#define ERROR(x)                                          \
    do                                                    \
    {                                                     \
        perror(x);                                        \
        printf("%s-%s-%d", __FILE__, __func__, __LINE__); \
        return -1;                                        \
    } while (0)

int createServer(const char *ip, unsigned short port);
int mainLoop(int servfd);
int handleClient(struct sockaddr_in client_addr, int actfd);
char *myGetString(char *buf, int size);
// 线程参数结构体
typedef struct
{
    char *ip;
    int port;
} thread_args_t;

// 线程函数 - 执行原本main函数的工作
void *server_main(void *arg)
{
    thread_args_t *args = (thread_args_t *)arg;

    printf("Thread: Starting server on %s:%d\n", args->ip, args->port);
    //创建服务器
    int servfd = createServer(args->ip, (unsigned short)args->port);
    if (servfd == -1)
    {
        printf("Thread: Failed to create server\n");
        free(args);
        return NULL;
    }
    //进入服务器主循环
    mainLoop(servfd);

    //服务期退出时关闭监听描述符
    close(servfd);
    free(args);
    return NULL;
}

int main(int argc, char *argv[])
{   //参数检查
    if (argc < 3)
    {
        printf("less argument\n");
        exit(0);
    }

    //解析端口号
    int port = 0;
    sscanf(argv[2], "%d", &port);
    if (port < 0 || port > 65535)//校验
    {
        printf("invalid port\n");
        exit(0);
    }
    
      // 初始化共享内存
    shm_addr = shm_init();
    if (shm_addr == (void*)-1) {
        perror("shm_init failed");
        exit(1);
    }

    // 创建共享内存处理线程
    pthread_t shm_thread;
    if (create_all_threads(&shm_thread) != 0) {
        perror("create_all_threads failed");
        exit(1);
    }

    // 准备线程参数,分配内存
    thread_args_t *args = malloc(sizeof(thread_args_t));
    if (args == NULL)
    {
        perror("malloc");
        exit(1);
    }
    args->ip = argv[1];
    args->port = port;

    // 创建线程，让线程执行原本main函数的工作
    pthread_t tid;
    if (pthread_create(&tid, NULL, server_main, (void *)args) != 0)
    {
        perror("pthread_create");
        free(args);
        exit(1);
    }

    printf("Main: Server thread created successfully\n");
    printf("Main: Thread ID: %lu\n", tid);

    // 等待服务器线程结束（实际上服务器是无限循环，这里只是为了演示）
    pthread_join(tid, NULL);

    printf("Main: Exiting...\n");
    return 0;
}

// 创建TCP服务器：完成 socket 创建、地址绑定、监听三步
// ip-绑定的IP地址，port-绑定的端口号
// 成功返回监听描述符（servfd），失败返回-1
int createServer(const char *ip, unsigned short port)
{
    // 1) socket()
    int servfd = socket(AF_INET, SOCK_STREAM, 0);
    if (servfd == -1)
    {
        ERROR("socket");
    }

    // 2) enter ip and port into struct sockaddr
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));//清空
    server_addr.sin_family = AF_INET;//IPV4协议
    server_addr.sin_port = htons(port);//端口
    inet_aton(ip, &server_addr.sin_addr);//IP地址

    // 3) bind()
    if (bind(servfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
    {
        ERROR("bind");
        servfd = -1;
    }

    // 4) listen()
    if (listen(servfd, 20) == -1)
    {
        ERROR("listen");
        servfd = -1;
    }

    return servfd;
}

int mainLoop(int servfd)
{
    while (1)// 无限循环，持续接收客户端连接
    {
        struct sockaddr_in client_addr;//存IP和端口号
        unsigned int len = sizeof(client_addr);
        int actfd = accept(servfd, (struct sockaddr *)&client_addr, &len);
        if (actfd == -1)
        {
            ERROR("accept");
            servfd = -1;
        }
        printf("[%s][%d] ", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        printf("client has been connected!\n");
        // 处理与该客户端的通信
        handleClient(client_addr, actfd);
    }
}
// 处理单个客户端的通信,用select实现标准输入和客户端消息的多路复用
// client_addr:客户端地址信息，actfd:与客户端通信的描述符
int handleClient(struct sockaddr_in client_addr, int actfd)
{
    char buf[64];
    char buf_send[64];
    fd_set fds;
    while (1)
    {
        FD_ZERO(&fds);
        FD_SET(0, &fds);
        FD_SET(actfd, &fds);

        memset(buf, 0, sizeof(buf));
        memset(buf_send, 0, sizeof(buf_send));

        // 调用select监听文件描述符,阻塞，知道有描述符准备就绪
        // 参数1：最大描述符+1（select会检查0~maxfd的描述符）
        // 参数2：读事件集合（监听是否有数据可读）
        // 参数3/4：写事件、异常事件集合
        // 参数5：超时时间,NULL无限阻塞
        int ret_select = select(actfd + 1, &fds, NULL, NULL, NULL);
        if (ret_select < 0)
        {
            printf("errorserverpoll.c\n");
            continue;
        }
        else if (ret_select == 0)
        {
            printf("select timeout\n");
            continue;
        }
        else if (ret_select > 0)
        {
            if (FD_ISSET(0, &fds) == 1)//检查标准输入是否就绪,服务器键盘输入消息要发送
            {
                myGetString(buf_send, sizeof(buf_send));
                 //发送消息给客户端,send阻塞调用，直到数据发送完成
                int ret = send(actfd, buf_send, sizeof(buf_send), 0);
                if (ret > 0)
                {
                    printf("send data succesd\n");
                }
                if (ret == 0)
                {
                    printf("disconnected\n");
                    break;
                }
                if (ret < 0)
                {
                    ERROR("send");
                    continue;
                }
            }
            if (FD_ISSET(actfd, &fds) == 1)//接收客户端消息
            {
                int ret = recv(actfd, buf, sizeof(buf)-1, 0);
                if (ret > 0)
                {
                    buf[ret] = '\0';  // 确保字符串终止
                     printf("[%s][%d] 接收消息: %s\n", 
                     inet_ntoa(client_addr.sin_addr), 
                     ntohs(client_addr.sin_port), 
                     buf);
                     msg_queue_send(&tcp_msg_queue, buf);
                }
                else if (ret == 0) 
                {
                    printf("客户端断开连接\n");
                    break;
                }
                else 
                {
                    ERROR("recv");
                    break;
                }
            }
        }
    }
}
char *myGetString(char *buf, int size)
{
    int len = 0;
    fgets(buf, size, stdin);
    len = strlen(buf);
    if (buf[len - 1] == '\n')
    {
        buf[len - 1] = '\0';
    }
    else
    {
        while (getchar() != '\n')
        {
        }
    }
    return buf;
}